package de.fhhannover.inform.hnefatafl.spiel;

import java.util.ArrayList;
import java.util.Observable;
import de.fhhannover.inform.hnefatafl.vorgaben.BoardContent;
import de.fhhannover.inform.hnefatafl.vorgaben.Cell;
import de.fhhannover.inform.hnefatafl.vorgaben.Move;

public class MoveChecker extends Observable{
	
	Logger  	logger;
	
	public MoveChecker(){
		logger = new Logger();
	}
	
	
	public boolean checkMove(boolean player,Move move,Field[][] board){
		
		if(checkPlayer(player, move, board)){
			if(checkMoveDirection(move, board)){
				if(checkMoveDistance(player, move, board)){
					if(checkTowers(player, move, board)){
						return true;
					}
					else return false;
				}
				else return false;
			}
			else return false;
		}
		else return false;
	}
	
	//--------------------------------------------------------------------
	//pruefen ob der Spieler auch den richtigen Spielstein setzt.
	
	private boolean checkPlayer(boolean player,Move move,Field[][] board){
		
		Cell source 		=  move.getFromCell();
		
		if((board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.ATTACKER && player == true)||
		   (board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.DEFENDER && player == false)||
		   (board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.KING && player == false)){
			return true;
		}else{
			//Attacker will zug machen, ist aber nicht an der reihe
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.ATTACKER && player == false){
				logger.writeToFile("Fehler: Angreifer ist nicht an der Reihe.");
			}
			//Defender will zug machen, ist aber nicht an der reihe
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.DEFENDER && player == true){
				logger.writeToFile("Fehler: Verteidiger will Zug machen, ist aber nicht an der Reihe.");
			}
			//Defender will Koenig setzen, ist aber nicht an der reihe
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.KING && player == true){
				logger.writeToFile("Fehler: Verteidiger will Zug machen, ist aber nicht an der Reihe.");
			}
			
			super.setChanged();
			super.notifyObservers(this);
			
			return false;
		}
	}
	
	//----------------------------------------------------------------------
	
	//pruefen ob der spielstein nach den  regeln gesetzt wird.
	
	private boolean checkMoveDirection(Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		Cell destination 	= move.getToCell();
		
		if(destination.getCol()+1 == source.getCol()+1 && destination.getRow()+1 != source.getRow()+1 ||
		   destination.getRow()+1 == source.getRow()+1 && destination.getCol()+1 != source.getCol()+1){
			
			return true;
			
		}else{
			logger.writeToFile("Fehler: Spielstein wurde versucht diagonal oder aufs Gleiche Feld zu setzen.");
			
			super.setChanged();
			super.notifyObservers(this);
			
			return false;
		}
		
	}
	
	//------------------------------------------------------------------
	
	//pruefen ob Spielsteine beim zug den weg versperren.
	
	private boolean checkMoveDistance(boolean player,Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		Cell destination 	= move.getToCell();
		
		//waagerechter Zug
		if((destination.getRow()+1 == source.getRow()+1)){
			
				if(source.getCol()+1 < destination.getCol()+1){
					
					for(int i = source.getCol()+2; i <= destination.getCol()+1;i++){
						//fals ein Stein im weg liegt von links nach rechts
						if(board[destination.getRow()+1][i].getContent() != BoardContent.EMPTY){
							if(player){
								logger.writeToFile("Fehler: Angreifer versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
							}
							if(!player){
								logger.writeToFile("Fehler: Verteidiger versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
							}
							
							super.setChanged();
							super.notifyObservers(this);
							
							return false;
						}
					}
					return true;
				
				}
				
				else if(source.getCol()+1 > destination.getCol()+1){
				
				for(int i = source.getCol(); i >= destination.getCol()+1;i--){
					//fals ein Stein im weg liegt von rechts nach links
					if(board[destination.getRow()+1][i].getContent() != BoardContent.EMPTY){
						if(player){
							logger.writeToFile("Fehler: Angreifer versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						if(!player){
							logger.writeToFile("Fehler: Verteidiger versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						
						super.setChanged();
						super.notifyObservers(this);
						
						return false;
					}
				}
				return true;
			}
		  }
		
		//senkerechter Zug
		else if((destination.getCol()+1 == source.getCol()+1)){
			
			if(source.getRow()+1 < destination.getRow()+1){
				
				for(int i = source.getRow()+2; i <= destination.getRow()+1;i++){
					//fals ein Stein im weg liegt von oben nach unten
					if(board[i][destination.getCol()+1].getContent() != BoardContent.EMPTY){
						if(player){
							logger.writeToFile("Fehler: Angreifer versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						if(!player){
							logger.writeToFile("Fehler: Verteidiger versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						
						super.setChanged();
						super.notifyObservers(this);
						
						return false;
					}
				}
				return true;
				
			}
			
			else if(source.getRow()+1 > destination.getRow()+1){
				
				for(int i = source.getRow(); i >= destination.getRow()+1;i--){
					//fals ein Stein im weg liegt von unten nach oben
					if(board[i][destination.getCol()+1].getContent() != BoardContent.EMPTY){
						if(player){
							logger.writeToFile("Fehler: Angreifer versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						if(!player){
							logger.writeToFile("Fehler: Verteidiger versucht von Feld "+source+" nach Feld "+destination+" zu bewegen, der Weg ist aber versperrt.");
						}
						
						super.setChanged();
						super.notifyObservers(this);
						
						return false;
					}
				}
				return true;
				
			}
		}
		return true;
	}
	
	//------------------------------------------------------------------------
	
	//pruefen ob Spielsteine au�er des Koenigs die Turmfelder betreten wollen.
	private boolean checkTowers(boolean player,Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		Cell destination 	= move.getToCell();
		
		//angreifer will Turmfeld betreten
		if(player == true){
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.ATTACKER){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)||
				   (destination.getCol() == 6 && destination.getRow() == 6)){
					
						logger.writeToFile("Fehler: Angreifer versucht das Turmfeld \\ Thronfeld "+board[destination.getRow()+1][destination.getCol()+1]+" zu betreten.");
						super.setChanged();
						super.notifyObservers(this);
					
						return false;
				}
				else{return true;}
			}	
		}
		//Verteidiger will Turmfeld betreten
		if(player == false){
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.DEFENDER){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)||
				   (destination.getCol() == 6 && destination.getRow() == 6)){
					
						logger.writeToFile("Fehler: Verteidiger versucht das Turmfeld \\ Thronfeld "+board[destination.getRow()+1][destination.getCol()+1]+" zu betreten.");
						super.setChanged();
						super.notifyObservers(this);
						
						return false;
				}
				else{return true;}
			}
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.KING){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)){
							return true;
						}
			}
		}
		return true;
	}
	
	//-------------------------------------------------------------------------
	
	
	private boolean checkMoveKI(boolean player,Move move,Field[][] board){
		
		if(checkPlayerKI(player, move, board)){
			if(checkMoveDirectionKI(move, board)){
				if(checkMoveDistanceKI(player, move, board)){
					if(checkTowersKI(player, move, board)){
						return true;
					}
					else return false;
				}
				else return false;
			}
			else return false;
		}
		else return false;
	}
	
	
	//--------------------------------------------------------------------
	//pruefen ob der Spieler auch den richtigen Spielstein setzt.
	
	private boolean checkPlayerKI(boolean player,Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		
		if((board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.ATTACKER && player == true)||
		   (board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.DEFENDER && player == false)||
		   (board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.KING && player == false)){
			return true;
		}else{
			return false;
		}
	}
	
	//----------------------------------------------------------------------
	
	//pruefen ob der spielstein nach den  regeln gesetzt wird.
	
	private boolean checkMoveDirectionKI(Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		Cell destination 	= move.getToCell();
		
		if(destination.getCol()+1 == source.getCol()+1 && destination.getRow()+1 != source.getRow()+1 ||
		   destination.getRow()+1 == source.getRow()+1 && destination.getCol()+1 != source.getCol()+1){
			
			return true;
			
		}else{
			return false;
		}
		
	}
	
	//------------------------------------------------------------------
	
	//pruefen ob Spielsteine beim zug den weg versperren.
	
	private boolean checkMoveDistanceKI(boolean player,Move move,Field[][] board){
		
		Cell source 		=  move.getFromCell();
		Cell destination 	=  move.getToCell();
		
		//waagerechter Zug
		if((destination.getRow()+1 == source.getRow()+1)){
			
				if(source.getCol()+1 < destination.getCol()+1){
					
					for(int i = source.getCol()+2; i <= destination.getCol()+1;i++){
						//fals ein Stein im weg liegt von links nach rechts
						if(board[destination.getRow()+1][i].getContent() != BoardContent.EMPTY){
							
							return false;
						}
					}
					return true;
				
				}
				
				else if(source.getCol()+1 > destination.getCol()+1){
				
				for(int i = source.getCol(); i >= destination.getCol()+1;i--){
					//fals ein Stein im weg liegt von rechts nach links
					if(board[destination.getRow()+1][i].getContent() != BoardContent.EMPTY){
					
						return false;
					}
				}
				return true;
			}
		  }
		
		//senkerechter Zug
		else if((destination.getCol()+1 == source.getCol()+1)){
			
			if(source.getRow()+1 < destination.getRow()+1){
				
				for(int i = source.getRow()+2; i <= destination.getRow()+1;i++){
					//fals ein Stein im weg liegt von oben nach unten
					if(board[i][destination.getCol()+1].getContent() != BoardContent.EMPTY){
						
						return false;
					}
				}
				return true;
				
			}
			
			else if(source.getRow()+1 > destination.getRow()+1){
				
				for(int i = source.getRow(); i >= destination.getRow()+1;i--){
					//fals ein Stein im weg liegt von unten nach oben
					if(board[i][destination.getCol()+1].getContent() != BoardContent.EMPTY){
						
						return false;
					}
				}
				return true;
				
			}
		}
		return true;
	}
	
	//------------------------------------------------------------------------
	
	//pruefen ob Spielsteine ausser des Koenigs die Turmfelder betreten wollen.
	private boolean checkTowersKI(boolean player,Move move,Field[][] board){
		
		Cell source 		= move.getFromCell();
		Cell destination 	= move.getToCell();
		
		//angreifer will Turmfeld betreten
		if(player == true){
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.ATTACKER){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)||
				   (destination.getCol() == 6 && destination.getRow() == 6)){
					
						return false;
				}
				else{return true;}
			}	
		}
		//Verteidiger will Turmfeld betreten
		if(player == false){
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.DEFENDER){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)||
				   (destination.getCol() == 6 && destination.getRow() == 6)){
					
						return false;
				}
				else{return true;}
			}
			if(board[source.getRow()+1][source.getCol()+1].getContent() == BoardContent.KING){
				if((destination.getCol() == 0 && destination.getRow() == 0)||
				   (destination.getCol() == 12 && destination.getRow() == 0)||
				   (destination.getCol() == 0 && destination.getRow() == 12)||
				   (destination.getCol() == 12 && destination.getRow() == 12)){
							return true;
						}
			}
		}
		return true;
	}
	
	//-------------------------------------------------------------------------
	

	//liefert eine Liste mit moeglichen zuegen zurueck
	public ArrayList<Move> possibleMoves(boolean player,Field[][] board){
		
		ArrayList<Field> stones = new ArrayList<Field>();
		ArrayList<Move> moves = new ArrayList<Move>();
		
		//Liste der Spielsteine des Agreifers erstellen,
		//die mommentan auf dem Spielfeld sind.
		if(player == true){
			for(int i = 1; i <= 13; i++){
				for(int j = 1; j <= 13; j++){
					if(board[i][j].getContent() == BoardContent.ATTACKER){
						stones.add(board[i][j]);
					}
				}
			}
		}
		//Liste der Spielsteine des Verteidigers erstellen,
		//die mommentan auf dem Spielfeld sind.
		else{
			for(int i = 1; i <= 13; i++){
				for(int j = 1; j <= 13; j++){
					if(board[i][j].getContent() == BoardContent.DEFENDER ||
					   board[i][j].getContent() == BoardContent.KING){
						stones.add(board[i][j]);
					}
				}
			}
		}
		
		//Erstellt eine Liste aller moeglichen zuege 
		//der Spielfiguren auf dem Spielfeld.
		for(int i = 0; i <= stones.size()-1; i++){
			for(int j = 0; j <= 12; j++){
				//schaut ob mit dem mommentanen Stein zuege nach
				//Osten oder Westen moeglich sind,
				//falls Ja, werden diese in einer Arraylist gespeichert.
				if(checkMoveKI(player, new Zug(new Field(stones.get(i).getCol(),stones.get(i).getRow()), new Field(j,stones.get(i).getRow())), board)){
					moves.add(new Zug(new Field(stones.get(i).getCol(),stones.get(i).getRow()), new Field(j,stones.get(i).getRow())));
				}
				//schaut ob mit dem mommentanen Stein zuege nach
				//Norden oder Sueden moeglich sind,
				//falls Ja, werden diese in einer Arraylist gespeichert.
				if(checkMoveKI(player, new Zug(new Field(stones.get(i).getCol(),stones.get(i).getRow()), new Field(stones.get(i).getCol(),j)), board)){
					moves.add(new Zug(new Field(stones.get(i).getCol(),stones.get(i).getRow()), new Field(stones.get(i).getCol(),j)));
				}
				
			}
		}
		return moves;
	}

	
}
